package com.unnamed.collisions.geometry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class Polygon {
	Point[] points;
	Transform transform;
	
	private float radius;
	
	public Polygon(Point[] p, float x, float y){
		this.points=p;
		transform = new Transform();
		
		for(Point point:points){
			float distance = (float) Math.sqrt(point.x*point.x+point.y*point.y);
			
			if(distance>radius){
				radius = distance;
			}
		}
	}
	
	public Polygon(Point[] p){
		this(p,0,0);
	}
	
	public float getRadius(){
		return this.radius;
	}
	
	public void translate(float x, float y){
		transform.translate(x,y,0);
	}
	
	public void rotate(float angle){
		transform.rotate(angle,0,0,1);
	}
	
	public void scale(float fx, float fy){
		transform.scale(fx, fy, 1);
	}
	
	public Point getTxPoint(int index){
		return transform.getTransform(points[index]);
	}
	
	public Point[] getTxPoints(){
		Point[] txPoints = new Point[points.length];
		
		for(int c=0;c<points.length;c++){
			txPoints[c] = transform.getTransform(points[c]);
		}
		
		return txPoints;
	}
	
	public Point getCenter(){
		return transform.getTransform(new Point(0,0));
	}
	
	public boolean intersects(Polygon p){
		Point pCenter = p.getCenter();
		
		for(int c=0;c<points.length;c++){
			for(int d=0;d<p.points.length;d++){
				Point i = edgeIntersection(
					points[c%points.length],
					points[(c+1)%points.length],
					p.points[d%p.points.length],
					p.points[(d+1)%p.points.length]
				);
						
				
				if(i!=null){
					return true;
				}
			}
		}
		
		return false;
	}
	
	public boolean intersects(Point a, Point b){
		for(int c = 0;c<points.length;c++){
			Point i = edgeIntersection(
				points[c%points.length],
				points[(c+1)%points.length],
				a,
				b
			);
			
			if(i!=null){
				return true;
			}
		}
		
		return false;
	}
	
//	public Polygon getIntersection(Polygon p){
//		List<Point> intP = new ArrayList<Point>();
//		
//		for(int c=0;c<points.length;c++){
//			for(int d=0;d<p.points.length;d++){
//				Point i = Edge.intersects(
//					points[c%points.length].x, 
//					points[c%points.length].y, 
//					points[(c+1)%points.length].x, 
//					points[(c+1)%points.length].y, 
//					p.points[d%p.points.length].x, 
//					p.points[d%p.points.length].y, 
//					p.points[(d+1)%p.points.length].x, 
//					p.points[(d+1)%p.points.length].y);
//				if(i!=null){
//					intP.add(i);
//				}
//			}
//		}
	
	public List<Point> getIntersection(Polygon p){
		List<Point> intP = new ArrayList<Point>();
		
//		Point pCenter = p.getCenter();
//		Point center = getCenter();
//		float pRadius = p.getRadius();
//		
//		float distance = center.distance(pCenter)-pRadius-radius;
//		
//		if(distance>0){
//			return intP;
//		}
//		
//		Point[] selfTx = getTxPoints();
		Point[] oTx = p.getTxPoints();
		
		
		for(int c=0;c<points.length;c++){
			Point a = getTxPoint(c%points.length);
			Point b = getTxPoint((c+1)%points.length);
			for(int d=0;d<p.points.length;d++){
				Point i = edgeIntersection(
					a,
					b,oTx[d%oTx.length], oTx[(d+1)%oTx.length]
				);
				//Point i = edgeIntersection(selfTx[(c%selfTx.length)], selfTx[(c+1)%selfTx.length], oTx[d%oTx.length], oTx[(d+1)%oTx.length]);
					
				if(i!=null){
					intP.add(i);
				}
			}
		}
		
		return intP;
	}
	
	public List<Point> getIntersection(Point a, Point b){
		List<Point> lp = new ArrayList<Point>();
		
		for(int c = 0;c<points.length;c++){
			Point i = edgeIntersection(
				getTxPoint(c%points.length),
				getTxPoint((c+1)%points.length),
				a,
				b
			);
			
			if(i!=null){
				lp.add(i);
			}
		}
		
		return lp;
	}
	
	private Point edgeIntersection(Point a, Point b, Point c, Point d){
		//float a.x,  a.y,  b.x,  b.y,  c.x,  c.y,  d.x,  d.y;
		
	    float s1_x, s1_y, s2_x, s2_y;
	    s1_x = b.x - a.x;     s1_y = b.y - a.y;
	    s2_x = d.x - c.x;     s2_y = d.y - c.y;

	    
	    
	    float s, t;
	    s = (-s1_y * (a.x - c.x) + s1_x * (a.y - c.y)) / (-s2_x * s1_y + s1_x * s2_y);
	    t = ( s2_x * (a.y - c.y) - s2_y * (a.x - c.x)) / (-s2_x * s1_y + s1_x * s2_y);

	    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
	    {
	    	Point i = new Point();
            i.x = a.x + (t * s1_x);
            i.y = a.y + (t * s1_y);
	        return i;
	    }else{
	    	return null;
	    }
	}
	
	private float getArea(){
		int i, j, n = points.length;
		double area = 0;

		for (i = 0; i < n; i++) {
			j = (i + 1) % n;
			area += points[i].x * points[j].y;
			area -= points[j].x * points[i].y;
		}
		area /= 2.0;
		return (float) (area);
	}
	public Point getMassCenter(){
		double cx = 0, cy = 0;
		double area = getArea();
		// could change this to Point2D.Float if you want to use less memory
		Point res = new Point();
		int i, j, n = points.length;

		double factor = 0;
		for (i = 0; i < n; i++) {
			j = (i + 1) % n;
			factor = (points[i].x * points[j].y
					- points[j].x * points[i].y);
			cx += (points[i].y + points[j].x) * factor;
			cy += (points[i].y + points[j].y) * factor;
		}
		area *= 6.0f;
		factor = 1 / area;
		cx *= factor;
		cy *= factor;
		
		res.x = (float) cx;
		res.y = (float) cy;
		
		
		return transform.getTransform(res);
	}
}
